<template>
  <div id="app">
    <div class="block-wrapper">
      <div
        :class="[
          'block',
          { active: user.some((a) => a.x === item.x && a.y === item.y) },
        ]"
        v-for="(item, index) in arr"
        :key="index"
      >
        <div class="material-icons" v-if="item.food">favorite</div>
      </div>
    </div>
    <div class="score">
      <div>分数：{{ score }}</div>
      <div>最高分数:{{ best }}</div>
    </div>
    <div class="retry">
      <div class="retry-btn" @click="retry">重来</div>
    </div>
    <div class="handler-wrappe">
      <div
        :class="['material-icons', 'up', { active: nextDirection === 'up' }]"
        @click="directionChange('up')"
      >
        keyboard_arrow_up
      </div>
      <div
        :class="[
          'material-icons',
          'left',
          { active: nextDirection === 'left' },
        ]"
        @click="directionChange('left')"
      >
        keyboard_arrow_left
      </div>
      <div
        :class="[
          'material-icons',
          'right',
          { active: nextDirection === 'right' },
        ]"
        @click="directionChange('right')"
      >
        keyboard_arrow_right
      </div>
      <div
        :class="[
          'material-icons',
          'down',
          { active: nextDirection === 'down' },
        ]"
        @click="directionChange('down')"
      >
        keyboard_arrow_down
      </div>
    </div>
    <div :class="['fail', { show: fail }]">失败</div>
  </div>
</template>

<script>
import random from 'random-number'
export default {
  name: 'App',
  data () {
    return {
      arr: [],
      user: [
        {
          x: 2,
          y: 13
        },
        {
          x: 2,
          y: 12
        },
        {
          x: 2,
          y: 11
        },
        {
          x: 2,
          y: 10
        },
        {
          x: 2,
          y: 9
        },
        {
          x: 2,
          y: 8
        },
        {
          x: 2,
          y: 7
        },
        {
          x: 2,
          y: 6
        },
        {
          x: 2,
          y: 5
        },
        {
          x: 2,
          y: 4
        },
        {
          x: 2,
          y: 3
        },
        {
          x: 2,
          y: 2
        }
      ],
      nextDirection: 'right',
      interval: null,
      score: 0,
      best: 0,
      food: null,
      fail: false,
      speed: 3
    }
  },
  methods: {
    blockInit () {
      for (let x = 0; x < 20; x++) {
        for (let y = 0; y < 20; y++) {
          this.arr.push({ x, y, food: false })
        }
      }
    },
    tick () {
      if (this.interval) {
        clearInterval(this.interval)
      }
      this.interval = setInterval(() => {
        let clone = JSON.parse(JSON.stringify(this.user))
        let user = JSON.parse(JSON.stringify(this.user))
        user.forEach((item, index) => {
          if (index === 0) {
            if (this.nextDirection === 'left') {
              item.y--
            } else if (this.nextDirection === 'right') {
              item.y++
            } else if (this.nextDirection === 'up') {
              item.x--
            } else if (this.nextDirection === 'down') {
              item.x++
            }
          } else {
            this.$set(user, index, clone[index - 1])
          }
        })
        // 没有吃到食物
        if (!this.eat(user)) {
          this.user = user
        }
        this.check()
      }, this.timeSpan)
    },
    check () {
      if (this.user.some((a) => a.x > 19 || a.x < 0 || a.y > 19 || a.y < 0)) {
        this.fail = true
        clearInterval(this.interval)
      }
      let user = JSON.parse(JSON.stringify(this.user))
      if (!this.chachong(user)) {
        this.fail = true
        clearInterval(this.interval)
      }
    },
    // user查重
    chachong (user) {
      if (user.length === 0) {
        return true
      } else {
        let item = user.shift()
        if (user.some((a) => a.x === item.x && a.y === item.y)) {
          return false
        } else {
          return this.chachong(user)
        }
      }
    },
    eat (user) {
      if (user.some((a) => a.x === this.food.x && a.y === this.food.y)) {
        this.user.unshift({
          x: this.food.x,
          y: this.food.y
        })
        this.food.food = false
        this.score++
        this.putFood()
        return true
      }
      return false
    },
    directionChange (direction) {
      // 不能与目前方向相反
      if (direction === 'left') {
        if (
          this.user.some(
            (a) => a.x === this.user[0].x && a.y === this.user[0].y - 1
          )
        ) {
          return
        }
      } else if (direction === 'right') {
        if (
          this.user.some(
            (a) => a.x === this.user[0].x && a.y === this.user[0].y + 1
          )
        ) {
          return
        }
      } else if (direction === 'up') {
        if (
          this.user.some(
            (a) => a.x === this.user[0].x - 1 && a.y === this.user[0].y
          )
        ) {
          return
        }
      } else if (direction === 'down') {
        if (
          this.user.some(
            (a) => a.x === this.user[0].x + 1 && a.y === this.user[0].y
          )
        ) {
          return
        }
      }
      this.nextDirection = direction
    },
    putFood () {
      if (this.food) {
        this.food.food = false
      }
      let empty = []
      this.arr.forEach((item) => {
        if (this.user.every((a) => a.x !== item.x || a.y !== item.y)) {
          empty.push(item)
        }
      })
      let index = random({ min: 0, max: empty.length, integer: true })
      empty[index].food = true
      this.food = empty[index]
    },
    retry () {
      this.user = [
        {
          x: 2,
          y: 4
        },
        {
          x: 2,
          y: 3
        },
        {
          x: 2,
          y: 2
        }
      ]
      this.tick()
      this.putFood()
      this.fail = false
      this.score = 0
      this.nextDirection = 'right'
    },
    keyUp () {
      document.onkeyup = (e) => {
        if (e.keyCode === 40) {
          this.nextDirection = 'down'
          this.directionChange('down')
        } else if (e.keyCode === 38) {
          this.directionChange('up')
        } else if (e.keyCode === 37) {
          this.directionChange('left')
        } else if (e.keyCode === 39) {
          this.directionChange('right')
        }
      }
    }
  },
  mounted () {
    this.blockInit()
    this.tick()
    this.putFood()
    this.keyUp()
  },
  watch: {
    score (val) {
      if (val > this.best) {
        this.best = val
      }
    }
  },
  computed: {
    timeSpan () {
      return 1000 / this.speed
    }
  }
}
</script>

<style lang="less" scoped>
#app {
  .block-wrapper {
    display: flex;
    flex-wrap: wrap;
    .block {
      width: 5vw;
      height: 5vw;
      text-align: center;
      box-sizing: border-box;
      background: #fefefe;
      border-left: 1px solid #eee;
      border-bottom: 1px solid #eee;
      &:nth-child(20n + 1) {
        border-left: 0;
      }
      &.active {
        background: #666;
      }
      .material-icons {
        font-size: 4vw;
        line-height: 5vw;
      }
    }
  }
  .score {
    margin: 20px;
  }
  .retry {
    position: absolute;
    right: 20px;
    top: calc(100vw + 30px);
    .retry-btn {
      width: 100px;
      border-radius: 4px;
      height: 24px;
      border: 1px solid #666;
      line-height: 24px;
      text-align: center;
      cursor: pointer;
    }
  }
  .handler-wrappe {
    position: absolute;
    bottom: 0;
    width: 100%;
    .material-icons {
      font-size: 36px;
      width: 40px;
      height: 40px;
      color: #333;
      border: 1px solid #333;
      border-radius: 50%;
      line-height: 40px;
      text-align: center;
      position: absolute;
      &.active {
        background: #333;
        color: #fff;
      }
      &.up {
        bottom: 90px;
        left: calc(50% - 20px);
      }
      &.left {
        bottom: 50px;
        left: calc(50% - 70px);
      }
      &.right {
        bottom: 50px;
        right: calc(50% - 70px);
      }
      &.down {
        bottom: 10px;
        left: calc(50% - 20px);
      }
    }
  }
  .fail {
    position: absolute;
    width: 100%;
    height: 40vh;
    background: rgba(0, 0, 0, 0.2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 40px;
    top: -40vh;
    transition: all 1s;
    &.show {
      top: 0;
    }
  }
}
</style>
